from rest_framework import serializers


class ObjectValidationError(Exception):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return f'ObjectValidationError:{self.msg}'


class ObjectSerializer:
    def __init__(self, obj_cls, obj_ser_cls):
        self.object_class = obj_cls
        self.object_serializer_class = obj_ser_cls

    def get_object_class(self):
        assert self.object_class is not None, 'object_class can not be None'
        return self.object_class

    def get_object_serializer_class(self):
        assert self.object_serializer_class is not None, 'object_serializer_class can not be None'
        return self.object_serializer_class

    def is_valid(self, data):
        serializer_class = self.get_object_serializer_class()
        serializer = serializer_class(data=data)
        try:
            serializer.is_valid(raise_exception=True)
        except serializers.ValidationError as e:
            raise ObjectValidationError(str(e))

    def object_serialize(self, obj):
        serializer_class = self.get_object_serializer_class()
        data = serializer_class(obj).data
        self.is_valid(data)
        return data

    def object_deserialize(self, data):
        deserializer_class = self.get_object_serializer_class()
        serializer = deserializer_class(data=data)
        try:
            serializer.is_valid(raise_exception=True)
            return serializer.create(data)
        except serializers.ValidationError as e:
            raise ObjectValidationError(str(e))


class BaseService:
    def __init__(self, obj_cls, obj_ser_cls, biz):
        self.object_serializer = ObjectSerializer(obj_cls, obj_ser_cls)
        self.biz_processor = biz

    def get_object_class(self, *args, **kwargs):
        assert self.object_serializer is not None, 'object_serializer can not be None'
        return self.object_serializer.get_object_class()

    def preform_create(self, data, *args, **kwargs):
        return self.biz_processor.create(data, *args, **kwargs)

    def create(self, obj):
        if not isinstance(obj, self.get_object_class()):
            raise TypeError(f'input object type({type(obj)}) is not the required')

        serialize_data = self.object_serializer.object_serialize(obj)
        ret = self.preform_create(serialize_data)

        return self.object_serializer.object_deserialize(ret)

    def retrieve(self, pk):
        data = self.biz_processor.retrieve(pk)
        if data:
            return self.object_serializer.object_deserialize(data)
        else:
            return None

    def preform_update(self, data, *args, **kwargs):
        pk = data.get('id')
        return self.biz_processor.update(pk, data, *args, **kwargs)

    def update(self, obj):
        if not isinstance(obj, self.get_object_class()):
            raise TypeError(f'input object type({type(obj)}) is not the required')

        serialize_data = self.object_serializer.object_serialize(obj)
        self.preform_update(data=serialize_data)
        return True

    def preform_destroy(self, pk, *args, **kwargs):
        return self.biz_processor.destroy(pk, *args, **kwargs)

    def destroy(self, pk):
        self.preform_destroy(pk)
        return True

    def list(self, *args, **kwargs):
        objs = list()
        data = self.biz_processor.list()
        for item in data:
            objs.append(self.object_serializer.object_deserialize(item))

        return objs
